#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <pthread.h> 
#include <time.h>
#include <signal.h>
#include <string.h>
#include <math.h>

#include "SDL/SDL.h"


#define LAM_PORT 36668
#define HEARTBEATS_PORT 36667
#define SERVER_PORT 36666
#define BUFLEN 512
#define GATE_NUM 28
#define T_MAX 20 
#define WIDTH 1024
#define HEIGHT 768
#define LAMPORT_NUM 5
#define LAMPORT_AGREE_NUM (LAMPORT_NUM-1)
#define REQ 1
#define OK 2
#define STATE_NO_CARE 1
#define STATE_REQ 2
#define STATE_CR 3
#define STATE_DONE 4

#define ACTION_INCREMENT 1
#define ACTION_SET 2
#define ACTION_NO_ADD 3

int lamport_action = 0;
int count = 0;
int lamport_agree_count = 0;
int lamp_counter = 0;
pthread_mutex_t mut; 
pthread_mutex_t lamp_seg_mut; 

int heartbeat_count = 0;
int g_seg_counter = 0;
static struct itimerval oldtv;
static struct itimerval oldtv_lamport;
char arg0[64];
char arg1[8];
char arg2[8];
char arg3[8];

int g_my_port = 0;
int semaph = 0;
int seg_num = 0;
int lamport_count = 0;
int lamport_switch = 0;
char g_my_ip[BUFLEN];
char g_other_ip[BUFLEN];
int g_other_port = 0;
typedef struct
{
	int state;
	char desc[10];
} LAMPORT_STATE;
LAMPORT_STATE lam_state;

struct seg_arguments
{
  unsigned int minval;	//min number of segments
  unsigned int maxval;	//max number of segments
  unsigned int thbeat;	//heartbeat time
}arg;

typedef struct node *link_seg;
typedef struct 
{
	char ip[BUFLEN];
	int  port;
	short alive;
} seginfo;

struct node {
    seginfo seg;
    link_seg next;
};
typedef struct lamp_node *lamp_link_seg;

typedef struct 
{
	char ip[BUFLEN];
	int  port;
} lamp_seginfo;


struct lamp_node {
    lamp_seginfo lamp_seg;
    lamp_link_seg next;
};


static link_seg head =NULL;
static lamp_link_seg lamp_head =NULL;



struct in_addr localInterface;
//struct sockaddr_in kill_recv_group;
struct sockaddr_in kill_last_groupSock;
struct sockaddr_in kill_all_groupSock;
struct sockaddr_in heartbeat_group_sock, s_addr_in;
struct sockaddr_in lamport_group_sock;
int lamp_socket;

pid_t srv_listen = -1;
int maxtime = 0;
int g_num_process = 0;
int g_kill_me = 0;
//pthread_mutex_t mut; 
char ip[BUFLEN];
static int noOfAliveThreads = 0;
pthread_t tid[T_MAX];
pthread_t g_thread;
pthread_t g_heartbeat_thread;
pthread_t g_lamport_thread;
FILE *g_test;

int msg_type;
int lamport_cr;
struct sockaddr_in group_sock;
char buf[BUFLEN]="0";
int socket_heartbeat=0;
FILE *fp = NULL;  //the log file
int seg_cnt = 0;
char seg[1024]="\0";
char logbuf[1024]="\0";




link_seg make_node (seginfo seg)
{
	link_seg p = malloc(sizeof(struct node));
	strcpy(p->seg.ip, seg.ip);
	p->seg.port = seg.port;
	p->seg.alive = 0;
	p->next = NULL;
	return p;
}
lamp_link_seg lamp_make_node (lamp_seginfo lamp_seg)
{
	lamp_link_seg p = malloc(sizeof(struct node));
	strcpy(p->lamp_seg.ip, lamp_seg.ip);
	p->lamp_seg.port = lamp_seg.port;

	p->next = NULL;
	return p;
}

void append_node(link_seg head, link_seg p)
{
	if(NULL == head)
	{
		p->next = NULL;
	}
	else
	{
		p->next = head->next;
	}
	head->next = p;
	
}
void free_node(link_seg p)
{
	free(p);
}
void lamp_free_node(lamp_link_seg p)
{
	free(p);
}

link_seg search(seginfo seg)
{
	link_seg p;
	for(p=head;p;p=p->next)
	{
		if((strcmp(seg.ip, p->seg.ip) == 0) && (p->seg.port == seg.port))
		{
			p->seg.alive = 1;
			return p;
		}
	}
	return NULL;
}
lamp_link_seg lamp_search(lamp_seginfo lamp_seg)
{
	lamp_link_seg p;
	for(p=lamp_head;p;p=p->next)
	{
		if((strcmp(lamp_seg.ip, p->lamp_seg.ip) == 0) && (p->lamp_seg.port == lamp_seg.port))
		{

			return p;
		}
	}
	return NULL;
}

void insert(link_seg p)
{
	p->next = head;
	head = p;
}
void lamp_insert(lamp_link_seg p)
{
	p->next = lamp_head;
	lamp_head = p;
}

void lamp_delete_from_list(lamp_link_seg p)
{
	lamp_link_seg pre;
	if(p == lamp_head)
	{
		lamp_head = p->next;
		return;
	}
	for(pre=lamp_head; pre; pre = pre->next)
	{
		if(pre->next == p )
		{
			pre->next = p->next;
			return;
		}
	}
}

void delete_from_list(link_seg p)
{
	link_seg pre;
	if(p == head)
	{
		head = p->next;
		return;
	}
	for(pre=head; pre; pre = pre->next)
	{
		if(pre->next == p )
		{
			pre->next = p->next;
			return;
		}
	}
}

void traverse(void (*visit)(link_seg))
{
	link_seg p;
		
	for(p=head;p;p=p->next)
	{
		visit(p);
	}
	return;
}
void destroy(void)
{
	link_seg q,p=head;
	while(p)
	{
		q=p;
		p=p->next;
		free_node(q);
	}
	return;
}
void push(link_seg p)
{
	insert(p);
}

link_seg pop(void)
{
	if(NULL == head)
	{
		return NULL;
	}
	else
	{
		link_seg p=head;
		head = head->next;
		return p;
	}
	return;
}

int hostname_to_ip(char * p_hostname , char* ip)
{
    struct hostent *he;
    struct in_addr **addr_list;
    int i;

    if ( (he = gethostbyname( p_hostname ) ) == NULL)
    {
        // get the host info
        printf("gethostbyname");
        return -1;
    }
    addr_list = (struct in_addr **) he->h_addr_list;
    for(i = 0; addr_list[i] != NULL; i++)
    {
        //Return the first one;
        strcpy(ip , inet_ntoa(*addr_list[i]) );
        return 0;
    }
    return -1;
}


void *send_heartbeat(void)
{


	struct in_addr localInterface;
	char hostname[BUFLEN] = "\0";
	char  ip[BUFLEN] = "\0";
	int ret;

	int len, ilen;
	heartbeat_count ++;
	len = sizeof( struct sockaddr);
	ilen = sizeof( s_addr_in);
	
	if ((socket_heartbeat=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
    	printf("socket err in send_heartbeat");
	
	memset((char *) &heartbeat_group_sock, 0, sizeof(heartbeat_group_sock));
	heartbeat_group_sock.sin_family = AF_INET;
	heartbeat_group_sock.sin_addr.s_addr = inet_addr("227.1.1.1");
	heartbeat_group_sock.sin_port = htons(36667);
        
	//Disable loopback so you do not receive your own datagrams.
	/*
	char loopch = 0;
	if(setsockopt(socket_heartbeat, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0)
	{
		perror("Setting IP_MULTICAST_LOOP error");
		close(socket_heartbeat);
		exit(1);
	}
	else
	{
		printf("Disabling the loopback...OK.");
	}
	*/

	gethostname(hostname, BUFLEN);
	if( -1 == (ret = hostname_to_ip(hostname, ip)) )
	{
		exit (0);
	}

	localInterface.s_addr = inet_addr(ip);
	
	if(setsockopt(socket_heartbeat, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
	{
		printf("Setting local interface error");
		return ;
	}	
	else
	{
		printf("Setting the local interface...OK\n");
	}
	
	while(1)
	{
		sprintf(buf, "%d",count);
		if (sendto(socket_heartbeat, buf, BUFLEN, 0, (struct sockaddr*)&heartbeat_group_sock, sizeof(heartbeat_group_sock) )==-1)
		{
			printf("sendto() in signal_handler_heartbeat");
			
		}
		//printf("before sleep\n");
		sleep(2);
		//printf("after sleep\n");
		
		count++;
	}

	close(socket_heartbeat);
	return ;
}

void *listen_thread(void)
{
	int s,ret,len, i, errno;
	struct sockaddr_in si_me, si_other;
	struct ip_mreq recv_group;
	char mbuf[512];
	char cport[5];
	char hostname[BUFLEN], ip[BUFLEN];
	seginfo seg;
	link_seg tmp;
	len = sizeof(struct sockaddr);
	if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)	
	{
		sprintf(logbuf,"socket err, errno %d", errno);
		printf(logbuf);
	}

	//REUSE THINGS	
	int reuse = 1;
	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
	{
		sprintf(logbuf,"Setting SO_REUSEADDR error. errno = %d", errno);
		printf(logbuf);
		close(s);
	}

	memset((char *) &si_me, 0, sizeof(si_me));
	si_me.sin_family = AF_INET;
	si_me.sin_port = htons(HEARTBEATS_PORT);
	si_me.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(s, (struct sockaddr *)&si_me, sizeof(si_me))==-1) 
	{
		printf("bind");
		close(s);
	}
	recv_group.imr_multiaddr.s_addr = inet_addr("227.1.1.1");
	
	gethostname(hostname, BUFLEN);
	if( -1 == (ret = hostname_to_ip(hostname, ip)) )
	{
		exit (0);
	}	

	recv_group.imr_interface.s_addr = inet_addr(ip);
	sprintf(logbuf, "ip in listen thread is %s", ip);
	printf(logbuf);

	if(setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&recv_group, sizeof(recv_group)) < 0)
	{
		sprintf(logbuf,"Adding multicast group error, errno = %d\n", errno);
		printf(logbuf);
		close(s);
	}
	printf("before recvfrom");
	while(1)
	{
		if ((recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *)&si_other, &len))==-1)
		{
			printf("recv err\n");
			return ;
		}
		
		sprintf(logbuf,"Received packet from %s:%d, Data: %s\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
		//printf(logbuf);
		seg.port = ntohs(si_other.sin_port);
		strcpy(seg.ip, inet_ntoa(si_other.sin_addr));
		//search this segment in the list.if not found, add it to the list
		tmp = search(seg);
		//printf("after search\n");
		if (NULL == tmp)
		{	
			printf("not found, insert\n");
			link_seg p_seg = make_node(seg);
			p_seg->next = head;
			insert(p_seg);
			sprintf(logbuf,"data is %s:%d\n", head->seg.ip, head->seg.port);
			printf(logbuf);
			lamport_count++;			
			printf("lamport_count is %d\n", lamport_count);
			if ( LAMPORT_NUM == lamport_count)
			{
				lamport_switch = 1;
				printf("start lamport\n");
				
			}
		}
		else
		{
			//printf("seg exist\n");
		}
	}
	close(s);

}

void *signal_handler_lamport(void)
{
	
}



int get_para(char *p_para, char *p_ip, int *p_port, int *p_msg_type, int *p_timestamp)
{
	char min_cnt[16]="\0";
	char list[4][16];
	char *p;
	int i = 0, j,k;
	p = p_para;
	for(j = 0; j < 4; j++)
	{
		for(k = 0; (*(p+i) != ',' && *(p+i) != '\0'); i++, k++)
		{
			min_cnt[k] = *(p+i);
		}
		i++;
		strcpy(list[j], min_cnt);
		memset(min_cnt, 0, 8);
	}

	strcpy(p_ip, list[0]);
	*p_port = atoi(list[1]);
	
	if ( 0 == (strncmp(list[2],"RQ",2) )) 
	{
		*p_msg_type = REQ;
	}
	else if  (0 == (strncmp(list[2],"OK",2))) 
	{
		*p_msg_type = OK;
	}
	else 
	{
		return 1;
	}
	*p_timestamp = atoi(list[3]);
	return 0;
	
}

void set_lamp_counter(int action, int value)
{
	pthread_mutex_lock(&mut); 
	if(ACTION_SET == action)
	{
		lamp_counter = value;
	}
	else if ( ACTION_INCREMENT == action)
	{		
		lamp_counter++;
	}
	else if ( ACTION_NO_ADD ==action)
	{
	}
	pthread_mutex_unlock(&mut); 
	return;
}

int lamp_send_init(void)
{
	struct in_addr lamp_localInterface;
	int ret = 0;
	char ip[BUFLEN],buf[BUFLEN], hostname[BUFLEN];
	struct sockaddr_in lamport_addr_in;

	int slen;
	if ((lamp_socket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
	printf("socket");

	
	memset((char *) &lamport_group_sock, 0, sizeof(lamport_group_sock));
	lamport_group_sock.sin_family = AF_INET;
	lamport_group_sock.sin_addr.s_addr = inet_addr("228.1.1.1");
	lamport_group_sock.sin_port = htons(LAM_PORT);

	
	gethostname(hostname, BUFLEN);
	if( -1 == (ret = hostname_to_ip(hostname, ip)) )
	{
		printf("hostname_to_ip in lamp_send_init");
		return ;
	}
	strcpy(g_my_ip, ip);

	lamp_localInterface.s_addr = inet_addr(ip);
	
	if(setsockopt(lamp_socket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&lamp_localInterface, sizeof(lamp_localInterface)) < 0)
	{
		printf("Setting local interface error");
		return ;
	}	
	bind(lamp_socket, (struct sockaddr *)&lamport_addr_in, sizeof(lamport_addr_in));
	
	slen = sizeof(lamport_addr_in);
	getsockname(lamp_socket, (struct sockaddr *)&lamport_addr_in, &slen);
	g_my_port  = ntohs(lamport_addr_in.sin_port);	
        printf("my_ip is %s, my_port:%d\n", g_my_ip, g_my_port);
	return 0;
}

int lamp_send(int msg_type, char *p_ip, int port)
{
	char buf[BUFLEN];
	
	set_lamp_counter(ACTION_INCREMENT, 0);
	if(msg_type == REQ)
	{		
		sprintf(buf, "%s,%d,RQ,%d", p_ip, port, lamp_counter);
	}
	else if(msg_type == OK)
	{
		sprintf(buf, "%s,%d,OK,%d", p_ip, port,lamp_counter);
	}
	else
	{
		printf("I've got a wrong msg_type:%d\n", msg_type);
		return 1;
	}
	printf("[%s]: I'm sending %s\n", lam_state.desc, buf);
	if (sendto(lamp_socket, buf, BUFLEN, 0,(struct sockaddr *) &lamport_group_sock, sizeof(lamport_group_sock))==-1)
	printf("sendto()");
	return 0;
}

int no_care_recv_proc(char *p_ip, int port)
{

	switch (msg_type)
	{
	case REQ:
	    
	    lamp_send(OK, p_ip, port);  //multicast----send OK and ++timestamp
	    break;
	
	
	case OK:	    
	    printf("In STATE_NO_CARE, I shouldn't receive OK from %s\n", p_ip);		 //multicast----do nothing
	    break;
	
	default: break;
	}

}

int compare_timestamp(void)
{
	return 0;
}
int req_recv_proc(char *p_ip, int port)
{
	int ret;
	switch (msg_type)
	{
	case REQ:	// when it's REQ, I either send Ok, or queue the segments for later use;	   
		if (ACTION_INCREMENT ==    lamport_action) //compare timestamp, send OK or check if I can enter the CR
		{
			ret = lamp_send(OK,p_ip,port);   //send Ok to the correspondant
		}
		else if (ACTION_SET == lamport_action)  //It means I win. Queue the request
		{
			//queue the segment
			queue_req(p_ip,port);
		}
		else
		{
			printf("I've got a wrong action %d\n", lamport_action);
			ret = 1;
		}
		break;
	
	
	case OK:	    
		lamport_agree_count++; //count_agree++
		printf("I've got lamport_agree_count %d\n", lamport_agree_count);
		if ((LAMPORT_AGREE_NUM) == lamport_agree_count)
		{
			
			printf("I've got all agree \n");
			lamport_cr = 1;
		}
		ret = 0;
	    break;
	
	default: 
		ret = 1;
		break;
	}
	return ret;

}

int queue_req(char *p_ip, int port)
{
	
	lamp_seginfo lamp_seg;
	lamp_link_seg tmp;
	//search first, if not find, insert
	strcpy(lamp_seg.ip, p_ip);
	lamp_seg.port = port;
	tmp = lamp_search(lamp_seg);
	//printf("after search\n");
	if (NULL == tmp)
	{	
		printf("not found, insert\n");
		lamp_link_seg p_lamp_seg = lamp_make_node(lamp_seg);
		pthread_mutex_lock(&lamp_seg_mut); 
		p_lamp_seg->next = lamp_head;
		lamp_insert(p_lamp_seg);
		pthread_mutex_unlock(&lamp_seg_mut); 
		sprintf(logbuf,"queued data is %s:%d\n", lamp_head->lamp_seg.ip, lamp_head->lamp_seg.port);
		printf(logbuf);
	}
	else
	{
		printf("lamport_seg exist%s:%d\n", p_ip, port);
	}
	return 0;
}

int cr_recv_proc(char *p_ip, int port)
{
	switch (msg_type)
	{
	case REQ:		   
	    queue_req(p_ip, port);  //queue it and send OK after finishing CR
	    break;
	
	
	case OK:	    
	    		 //do nothing
	    break;
	
	default: break;
	}

}

int counter_compare(int timestamp)
{
	if(timestamp > lamp_counter)  // I'm lower than him;I win.
	{
		
		set_lamp_counter(ACTION_SET,timestamp);
		lamport_action = ACTION_SET;
	}
	else
	{
		set_lamp_counter(ACTION_NO_ADD,0);//increment
		lamport_action = ACTION_NO_ADD;
	}
	return 0;
}

void *recv_thread(void)
{

	struct sockaddr_in si_other;
	struct sockaddr_in si_me;
	struct ip_mreq lamp_recv_group;
	char hostname[BUFLEN], ip[BUFLEN];
	int timestamp;
	int ret;
	int s_recv;
	int slen = sizeof(struct sockaddr);
	int errno;
	char para[BUFLEN];
	char recv_buf[512];

	if ((s_recv=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)	    
	{
		sprintf(logbuf,"socket in kill_receive err, errno = %d", errno);
		printf(logbuf);
		return ;
	}
	
	//REUSE THINGS	
	int reuse = 1;
	if(setsockopt(s_recv, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
	{
		sprintf(logbuf,"Setting SO_REUSEADDR error. errno = %d", errno);
		printf(logbuf);
		close(s_recv);
	}
	memset((char *) &si_me, 0, sizeof(si_me));

	si_me.sin_family = AF_INET;
	si_me.sin_port = htons(LAM_PORT);
	si_me.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(s_recv, (struct sockaddr *)&si_me, sizeof(si_me))==-1)
	{
		sprintf(logbuf,"bind err in kill_receive, errno = %d", errno);
		printf(logbuf);
		close(s_recv);
		return ;
	}

	
	lamp_recv_group.imr_multiaddr.s_addr = inet_addr("228.1.1.1");
	gethostname(hostname, BUFLEN);
        if( -1 == (ret = hostname_to_ip(hostname, ip)) )
        {
                printf("hostname_to_ip in recv_thread");
        }

	lamp_recv_group.imr_interface.s_addr = inet_addr(ip);
	sprintf(logbuf, "ip in lamport recv thread is %s\n", ip);
	printf(logbuf);
	
	if(setsockopt(s_recv, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&lamp_recv_group, sizeof(lamp_recv_group)) < 0)
	{
		sprintf(logbuf,"Adding multicast group error, errno = %d\n", errno);
		printf(logbuf);
		close(s_recv);
	}
	char recv_ip[BUFLEN], packet_ip[BUFLEN];
	int recv_port, packet_port;
	while (recvfrom(s_recv, recv_buf, 512, 0, (struct sockaddr *)&si_other, &slen)!=-1) 
	{
		sprintf(logbuf,"[%s]: receive packet from %s:%d, Data: %s\n", lam_state.desc,inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), recv_buf);
		printf(logbuf);
		strcpy(recv_ip, inet_ntoa(si_other.sin_addr));
		recv_port = ntohs(si_other.sin_port);
		if((0 == strcmp(recv_ip, g_my_ip)) && (recv_port == g_my_port))  // it means I received my own packet
		{
			//printf("I received my own packet. Do nothing\n");
			continue;
		}
		
		ret = get_para(recv_buf, packet_ip, &packet_port,&msg_type,&timestamp);
		if ( ret != 0)		
		{			
			sprintf(logbuf, "get_para failed. para is %s", recv_buf);	
			printf(logbuf);		
			close(s_recv);		
			
		}
		printf(" I received the data is ip:%s, port:%d, msg_type:%d, timestamp %d\n", packet_ip, packet_port, msg_type,timestamp);
		if((strcmp(packet_ip, "1.1.1.1") == 0) && (packet_port == 1))
		{
			printf("Before comparison the lamp_counter is %d\n", lamp_counter);
			counter_compare(timestamp);		
			printf("After comparison  the lamp_counter is %d\n", lamp_counter);			
			switch (lam_state.state)
			{
				case STATE_NO_CARE:	// during this state, I only receive REQ, send OK;	    
				    no_care_recv_proc(recv_ip, recv_port);
				    break;


				case STATE_REQ:	        // during this state, I receive REQ and OK,  when it's REQ, I either send Ok, or queue the segments for later use;
							// when it's OK, increment lamport_agree_count
				    req_recv_proc(recv_ip, recv_port);
				    break;

				case STATE_CR:	        //during this state, I only receive REQ, and queue the segments to send OK after finishing CR
				    cr_recv_proc(recv_ip, recv_port);
				    break;
				case STATE_DONE:
					printf("I've done\n");
					lamp_send(OK, recv_ip, recv_port);
				    break;

				default: 
					printf("state is unknown %d\n", lam_state.state);
					break;
			}
		}
		else if (( strcmp(packet_ip, g_my_ip) == 0) && (packet_port == g_my_port))
		{
			printf("Before comparison the lamp_counter is %d\n", lamp_counter);
			counter_compare(timestamp);		
			printf("After comparison  the lamp_counter is %d\n", lamp_counter);
			//we need to create a list to store the segment info
			switch (lam_state.state)
			{
				case STATE_NO_CARE:	// during this state, I only receive REQ, send OK;	    
				    no_care_recv_proc(packet_ip, packet_port);
				    break;


				case STATE_REQ:	        // during this state, I receive REQ and OK,  when it's REQ, I either send Ok, or queue the segments for later use;
							// when it's OK, increment lamport_agree_count
				    req_recv_proc(packet_ip, packet_port);
				    break;

				case STATE_CR:	        //during this state, I only receive REQ, and queue the segments to send OK after finishing CR
				    cr_recv_proc(packet_ip, packet_port);
				    break;    
				case STATE_DONE:
				    printf("I've done\n");
				    lamp_send(OK, packet_ip, packet_port);
			            break;

				default: 
					printf("state is unknown %d\n", lam_state.state);
					break;
			}
		}
		else
		{
			//printf("It's none of my business! recv:%s:%d packet:%s:%d\n", recv_ip, recv_port, packet_ip, packet_port);
		}

	}		    

	printf("recvfrom err in lamport_receive. errno = %d\n", errno);
	close(s_recv);
	return;
	
}
void lamp_respond_ok_to_queued(void)
{
	lamp_link_seg p;
	char *p_ip;
	int port;
	
	for(p = lamp_head; p; p=p->next)
	{
		strcpy(p_ip, p->lamp_seg.ip);
		port = p->lamp_seg.port;
		printf("I need to send OK to %s:%d\n", p_ip, port);
		//lock		
		pthread_mutex_lock(&lamp_seg_mut); 
		lamp_delete_from_list(p);
		//unlock		
		pthread_mutex_unlock(&lamp_seg_mut); 
		lamp_free_node(p);
		printf("I'm sending OK to %s:%d\n", p_ip, port);
		lamp_send(OK,p_ip,port);
	}
}

void lamport(void)
{
	int ret;
	
	memset(&lam_state, 0, sizeof(lam_state));	
	lam_state.state = STATE_NO_CARE;  // STATE_NO_CARE
	pthread_mutex_init(&mut,NULL);
	pthread_mutex_init(&lamp_seg_mut,NULL);
	
	pthread_create(&g_lamport_thread,NULL,(void*)recv_thread,NULL);
	printf("thread is %d\n");
	ret = lamp_send_init();   //remember to close the socket when necessary
	if ( 0 != ret)
	{
		printf("send_init failed\n");
		return;
	}
	
	while(1)
	{
		strcpy(lam_state.desc, "STATE_NO_CARE");
		printf("STATE_NO_CARE\n");
		time_t lt;
		int timea;
		
		timea = (g_lamport_thread%20);
		printf("I will sleep for %d seconds\n", timea);
		sleep(timea);
		lam_state.state = STATE_REQ;  // STATE_REQ
		strcpy(lam_state.desc, "STATE_REQ");
		printf("STATE_REQ\n");
		lamp_send(REQ, "1.1.1.1", 1);

		
		while(lamport_cr != 1)
		{
		}
		lam_state.state = STATE_CR;  // STATE_REQ
		strcpy(lam_state.desc, "STATE_CR");

		printf("I've entered the CR!!!!\n");
		sleep(5);
		//send ok to the segments queued in the list		
		lam_state.state = STATE_DONE;
		strcpy(lam_state.desc, "STATE_DONE");
		lamp_respond_ok_to_queued();
		while(1)
		{
		}
		
	}
		
	
}

int main(int argc, char *argv[])
{

	unsigned int seg_counter = 0;
	unsigned int gate_num;


	int i, errno; 
	int segment_already_stored = 0;
	int ret,zw=0;
	struct sockaddr_in si_me, si_other;
	int s, slen=sizeof(si_other);

	char tmp[BUFLEN];
	char pname[BUFLEN];
	char hostname[BUFLEN], ip[BUFLEN];
	pid_t main_pid;
	int sqrtcount;
	int num_thread;
        
	gethostname(hostname, BUFLEN);
	if( -1 == (ret = hostname_to_ip(hostname, ip)) )
	{
		exit (0);
	}	

        //create a thread to receive packet
	pthread_create(&g_thread,NULL,(void*)listen_thread,NULL);
        pthread_create(&g_heartbeat_thread,NULL,(void*)send_heartbeat,NULL);

	while(lamport_switch != 1)
	{
	}
	printf("lamport time\n");
	lamport();
	return 0;

}






